Imports System.Configuration.ConfigurationManager
Imports AZROLESLib
Imports System.Web
Imports System.Web.Security
Imports System.DirectoryServices

Public Class AzManRoleProvider
    Inherits System.Web.Security.RoleProvider


#Region "Members and Properties"

    Private _AzManStore As New AzAuthorizationStore()
    Private _azApp As IAzApplication
    Private p_applicationName As String

    Public Overrides Property ApplicationName() As String
        Get
            Return p_applicationName
        End Get
        Set(ByVal Value As String)
            p_applicationName = Value
        End Set
    End Property

#End Region

#Region "Authorization Related Methods"

    Public Overrides Sub Initialize(ByVal name As String, ByVal config As Specialized.NameValueCollection)
        Me.p_applicationName = config.Item("applicationName")
        MyBase.Initialize(name, config)

        Me._AzManStore.Initialize(0, Convert.ToString(ConnectionStrings(config.Item("connectionStringName"))), Nothing)
        Me._azApp = Me._AzManStore.OpenApplication(Me.p_applicationName)
    End Sub

    Public Overrides Function IsUserInRole(ByVal username As String, ByVal roleName As String) As Boolean
        'Call the embedded method for retrieving the Roles list for this user.
        Dim roles() As String = Me.GetRolesForUser(username)
        If IsNothing(roles) Then
            Return False
        End If
        Dim m_blnFoundMatch As Boolean = False

        'Loop through the results to see if there is a match.
        For Each objRole As String In roles
            If objRole.Equals(roleName, StringComparison.OrdinalIgnoreCase) Then
                'A match was found.
                m_blnFoundMatch = True

                'Exit out of the routine.
                Exit For
            End If
        Next

        'Return the value.
        Return m_blnFoundMatch
    End Function

#End Region

#Region "Methods dealing with fetching User's role information"

    Public Overrides Function GetRolesForUser(ByVal username As String) As String()
        Try
            Dim user As MembershipUser = Membership.GetUser(username)
            Dim context As IAzClientContext = _azApp.InitializeClientContextFromStringSid(user.ProviderUserKey.ToString, 1, Nothing)

            'Get the roles in an object array.
            Dim roles() As Object = CType(context.GetRoles(""), Object()) 'This is using an empty SCOPE in the GetRoles method.

            'Convert all of the internal contents to the String represenation for returning from the function.
            Return Array.ConvertAll(roles, New Converter(Of Object, String)(AddressOf GetRoleStringRepresentation))
        Catch ex As Exception
            Return Nothing
        End Try
    End Function


    Public Shared Function GetRoleStringRepresentation(ByVal CurrentRole As Object) As String
        Return CurrentRole.ToString
    End Function


#End Region

#Region "Methods for Creating, Deleting and Managing Roles"

    Public Overrides Sub CreateRole(ByVal roleName As String)
        Dim task As IAzTask = _azApp.CreateTask(roleName, Nothing)
        task.IsRoleDefinition = True
        task.Submit(0, Nothing)

        Dim role As IAzRole = _azApp.CreateRole(roleName, Nothing)
        role.AddTask(roleName, Nothing)
        role.Submit(0, Nothing)
    End Sub


    Public Overrides Function DeleteRole(ByVal roleName As String, ByVal thrownOnPopulatedRole As Boolean) As Boolean
        'Delete the role.
        _azApp.DeleteRole(roleName, Nothing)

        'Delete the associated Task.
        _azApp.DeleteTask(roleName, Nothing)
    End Function


    Public Overrides Function RoleExists(ByVal roleName As String) As Boolean
        Dim roles(_azApp.Roles.Count - 1) As String
        Dim m_blnFoundIt As Boolean = False

        'Loop through the results and add the members.
        For i As Integer = 1 To _azApp.Roles.Count
            'Get a reference to the current role.
            Dim objCurrentRole As IAzRole = _azApp.Roles(i)

            'Add the role to the array.
            If String.Equals(objCurrentRole.Name, roleName) Then
                m_blnFoundIt = True

                'Exit out of the routine.
                Exit For
            End If
        Next

        'Return the value.
        Return m_blnFoundIt
    End Function


    Public Overrides Sub AddUsersToRoles(ByVal usernames As String(), ByVal roleNames As String())
        'Loop through all of the users and roles to add them as needed.
        For Each objCurrentUser As String In usernames
            'Loop through each of the inner role members.
            For Each objCurrentRole As String In roleNames
                Dim user As MembershipUser = Membership.GetUser(objCurrentUser)
                Dim role As IAzRole = _azApp.OpenRole(objCurrentRole, Nothing)
                role.AddMember(user.ProviderUserKey.ToString, Nothing)
                role.Submit(0, Nothing)
            Next
        Next
    End Sub


    Public Overrides Sub RemoveUsersFromRoles(ByVal usernames As String(), ByVal roleNames As String())
        'Loop through all of the users and roles to remove them as needed.
        For Each objCurrentUser As String In usernames
            'Loop through each of the inner role members.
            For Each objCurrentRole As String In roleNames
                Dim user As MembershipUser = Membership.GetUser(objCurrentUser)
                Dim role As IAzRole = _azApp.OpenRole(objCurrentRole, Nothing)
                role.DeleteMember(user.ProviderUserKey.ToString, Nothing)
                role.Submit(0, Nothing)
            Next
        Next
    End Sub


    Public Overrides Function GetUsersInRole(ByVal roleName As String) As String()
        'Declare local variables.
        Dim _Users As New List(Of String)

        For Each _memUser As MembershipUser In Membership.GetAllUsers()
            If Roles.IsUserInRole(_memUser.UserName, roleName) Then
                _Users.Add(_memUser.UserName)
            End If
        Next
        Return _Users.ToArray()
    End Function


    Public Overrides Function GetAllRoles() As String()
        'Declare local variables.
        Dim roles(_azApp.Roles.Count - 1) As String

        'Loop through the results and add the members.
        For i As Integer = 1 To _azApp.Roles.Count
            'Get a reference to the current role.
            Dim objCurrentRole As IAzRole = _azApp.Roles(i)

            'Add the role to the array.
            roles.SetValue(objCurrentRole.Name, i - 1)
        Next

        'Return the value.
        Return roles
    End Function

    Public Overrides Function FindUsersInRole(ByVal roleName As String, ByVal usernameToMatch As String) As String()
        Throw New NotSupportedException
    End Function

#End Region

#Region "Application Group Management Methods"

    Public Sub CreateApplicationGroup(ByVal groupName As String)
        'Create the group.
        _azApp.CreateApplicationGroup(groupName, Nothing)
    End Sub

#End Region

#Region "Operations and Tasks"

    Public Function GetAllOperations() As List(Of IAzOperation)
        Return Me.GetAllOperations(HttpContext.Current.User.Identity.Name.ToString)
    End Function

    Public Function GetAllOperations(ByVal username As String) As List(Of IAzOperation)
        Dim _operations As New List(Of IAzOperation)

        For Each _role As String In Roles.GetRolesForUser(username)
            Dim _azRole As IAzRole = Me._azApp.OpenRole(_role)
            For Each _roleName As Object In _azRole.Tasks
                Dim _azRoleTask As IAzTask = Me._azApp.OpenTask(_roleName.ToString)
                Me.GetTasks(_azRoleTask, _operations)
            Next
        Next

        Return _operations
    End Function

    Private Sub GetTasks(ByVal azTask As IAzTask, ByRef operationsList As List(Of IAzOperation))
        For Each _taskName As Object In azTask.Tasks
            Dim _azTask As IAzTask = Me._azApp.OpenTask(_taskName.ToString)
            If _azTask.IsRoleDefinition = 1 Then
                Me.GetTasks(_azTask, operationsList)
            Else
                Me.GetOperations(_azTask, operationsList)
            End If
        Next
    End Sub

    Private Sub GetOperations(ByVal azTask As IAzTask, ByRef operationsList As List(Of IAzOperation))
        For Each _operationName As Object In azTask.Operations
            Dim _azOperation As IAzOperation = Me._azApp.OpenOperation(_operationName)
            operationsList.Add(_azOperation)
        Next
    End Sub

    Public Function IsOperationAllowed(ByVal userName As String, ByVal operationName As String) As Boolean
        Dim blnAllowed As Boolean = False

        Dim _operations As List(Of IAzOperation) = Me.GetAllOperations(userName)

        For Each azOperation As IAzOperation In _operations
            If (azOperation.Name.ToLower = operationName.ToLower) AndAlso _
                Me.IsOperationAllowed(azOperation, userName) Then
                blnAllowed = True
                Exit For
            End If
        Next

        Return blnAllowed
    End Function

    Private Const NO_ERROR As Integer = 0
    Private Function IsOperationAllowed(ByVal pOperation As IAzOperation, ByVal pUsername As String) As Boolean
        Dim _User As MembershipUser = Membership.GetUser(pUsername)
        Dim userContext As IAzClientContext = _azApp.InitializeClientContextFromStringSid(_User.ProviderUserKey.ToString, 1, Nothing)

        'Check if user has access to the operations
        Dim operationIds() As Object = {pOperation.OperationID}
        Dim scope() As Object = {String.Empty}

        Dim result() As Object = userContext.AccessCheck("Auditstring", scope, operationIds)

        'Test the integer array we got back to see which operations are authorized
        If (result(0) = NO_ERROR) Then
            Return True
        Else
            Return False
        End If
    End Function

#End Region

End Class